﻿#include "xpushbuttonfunction_p.h"

XPushButtonFunctionPrivate::XPushButtonFunctionPrivate()
    : displayEnable(true),
      pushButtonBoolStatus(false),
      defaultText("功能"),
      textBuffer(),
      LeftmousePressed(false),
      mousePressPoint(0, 0)
{
    defaultStyleSheet = "XPushButtonFunction{"
                        "background-color: rgb(50,197,100);"
                        "color: black;"
                        "border-radius: 10px;"
                        "border-top: 1px groove gray;"
                        "border-left: 1px groove gray;"
                        "border-right: 3px groove gray;"
                        "border-bottom: 3px groove gray;"
                        "border-style: outset;"
                        "}"
                        ""
                        "XPushButtonFunction:hover{"
                        "background-color: rgb(212,12,24);"
                        "color: black;"
                        "border-radius: 10px;"
                        "border-top: 1px groove gray;"
                        "border-left: 1px groove gray;"
                        "border-right: 3px groove gray;"
                        "border-bottom: 3px groove gray;"
                        "border-style: outset;"
                        "}"
                        ""
                        "XPushButtonFunction:pressed{"
                        "background-color: rgb(122,100,205);"
                        "color: black;"
                        "border-radius: 10px;"
                        "border-top: 1px groove black;"
                        "border-left: 1px groove black;"
                        "border-right: 1px groove black;"
                        "border-bottom: 1px groove black;"
                        "border-style: inset;"
                        "padding-left: 3px;"
                        "padding-top: 3px;"
                        "}";
}

XPushButtonFunctionPrivate::~XPushButtonFunctionPrivate()
{

}

/*!
 * \brief XPushButtonFunctionPrivate::xMapClear
 * \param map
 */
void XPushButtonFunctionPrivate::xMapClear(XMap &map)
{
    map.xFunctionMap.clear();
    map.functionMap.clear();
    map.length = 0;
}

XPushButtonFunction::XPushButtonFunction(QWidget *parent)
    : QPushButton(parent),
      xPushButtonFunctionP(new XPushButtonFunctionPrivate),
      traversalInstanceStatus(false)
{
    this->setStyleSheet(xPushButtonFunctionP->defaultStyleSheet);
    update();

    worker = new XPushButtonFunctionWorker(this);
    workerThread = new QThread;

    worker->moveToThread(workerThread);

    connect(workerThread, SIGNAL(started()), worker, SLOT(doWork()));
    connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);

    workerThread->start();
}

XPushButtonFunction::~XPushButtonFunction()
{
    //关闭线程
    if(workerThread->isRunning())
    {
        //停止线程
        if(worker)
        {
            worker->stop();
        }

        workerThread->quit();
        workerThread->wait();
    }

    xPushButtonFunctionP->xMapClear(xPushButtonFunctionP->pressInstanceMap);
    xPushButtonFunctionP->xMapClear(xPushButtonFunctionP->pressStatusMap);
    xPushButtonFunctionP->xMapClear(xPushButtonFunctionP->releaseInstanceMap);
    xPushButtonFunctionP->xMapClear(xPushButtonFunctionP->releaseStatusMap);

    delete xPushButtonFunctionP;
}

/*!
    \property XPushButtonFunction::displayEnable
    \brief control the XPushButtonFunction whether or not display

    True or False corresponds to display or undisplay.

    The default DisplayEnable is true.

    \sa indent
*/
bool XPushButtonFunction::getDisplayEnable() const
{
    return xPushButtonFunctionP->displayEnable;
}

void XPushButtonFunction::setDisplayEnable(bool enable)
{
    if(xPushButtonFunctionP->displayEnable == enable)
        return;
    xPushButtonFunctionP->displayEnable = enable;

    if(!xPushButtonFunctionP->displayEnable)
    {
        xPushButtonFunctionP->textBuffer = text();
        setText(NULL);
    }
    else
    {
        setText(xPushButtonFunctionP->textBuffer);
    }

    this->update();
}

/*!
    \reimp
*/
void XPushButtonFunction::paintEvent(QPaintEvent *ev)
{
    //绘制准备工作,启用反锯齿
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    this->setText(xPushButtonFunctionP->defaultText);

    QPushButton::paintEvent(ev);
}

/*!
 * \brief XPushButtonFunction::enterEvent
 * \param ev
 */
void XPushButtonFunction::enterEvent(QEvent *ev)
{
    if(QEvent::Enter == ev->type())
    {
        QCursor cursor;                           //创建光标对象
        cursor.setShape(Qt::PointingHandCursor);  //设置光标形状(指)
        setCursor(cursor);                        //使用光标
    }
    QPushButton::enterEvent(ev);
}

/*!
 * \brief XPushButtonFunction::leaveEvent
 * \param ev
 */
void XPushButtonFunction::leaveEvent(QEvent *ev)
{
    if(QEvent::Leave == ev->type())
    {
        QCursor cursor;                           //创建光标对象
        cursor.setShape(Qt::ArrowCursor);         //设置光标形状(指)
        setCursor(cursor);                        //使用光标
    }
    QPushButton::leaveEvent(ev);
}

/*!
 * \brief XPushButtonFunction::mousePressEvent
 * \param ev
 */
void XPushButtonFunction::mousePressEvent(QMouseEvent *ev)
{
    if(Qt::LeftButton == ev->button())
    {
        //设置左键按下状态为true
        xPushButtonFunctionP->LeftmousePressed = true;
        xPushButtonFunctionP->mousePressPoint = ev->globalPos();

        //设置遍历瞬时函数列表标志为true
        traversalInstanceStatus = true;
        //遍历按下时函数列表
        traversalPressInstanceMap();
        //设置遍历瞬时函数列表标志为false
        traversalInstanceStatus = false;
        //设置按钮状态为true
        xPushButtonFunctionP->pushButtonBoolStatus = true;

        QCursor cursor;                         //创建光标对象
        cursor.setShape(Qt::ClosedHandCursor);  //设置光标形状(小手)
        setCursor(cursor);                      //使用光标
    }
    QPushButton::mousePressEvent(ev);
}

/*!
 * \brief XPushButtonFunction::mouseReleaseEvent
 * \param ev
 */
void XPushButtonFunction::mouseReleaseEvent(QMouseEvent *ev)
{
    if(Qt::LeftButton == ev->button())
    {
        //设置左键按下状态为false
        xPushButtonFunctionP->LeftmousePressed = false;

        //设置遍历瞬时函数列表标志为true
        traversalInstanceStatus = true;
        //遍历释放时函数列表
        traversalReleaseInstanceMap();
        //设置遍历瞬时函数列表标志为false
        traversalInstanceStatus = false;
        //设置按钮状态为false
        xPushButtonFunctionP->pushButtonBoolStatus = false;

        QCursor cursor;                           //创建光标对象
        cursor.setShape(Qt::PointingHandCursor);  //设置光标形状(指)
        setCursor(cursor);                        //使用光标
    }
    QPushButton::mouseReleaseEvent(ev);
}

/*!
 * \brief XPushButtonFunction::mouseMoveEvent
 * \param ev
 */
void XPushButtonFunction::mouseMoveEvent(QMouseEvent *ev)
{
    // 鼠标左键拖动移动
    if(xPushButtonFunctionP->LeftmousePressed)
    {
        double mouseDx = ev->globalPos().x() - xPushButtonFunctionP->mousePressPoint.x();
        double mouseDy = ev->globalPos().y() - xPushButtonFunctionP->mousePressPoint.y();
        xPushButtonFunctionP->mousePressPoint = ev->globalPos();

        double myLabelNewx = this->x() + mouseDx;
        double myLabelNewy = this->y() + mouseDy;

        if(myLabelNewx < 0)
            myLabelNewx = 0;
        if(myLabelNewx + this->width() > QApplication::activeWindow()->width())
            myLabelNewx = QApplication::activeWindow()->width() - this->width();
        if(myLabelNewy < 0)
            myLabelNewy = 0;
        if(myLabelNewy + this->height() > QApplication::activeWindow()->height())
            myLabelNewy = QApplication::activeWindow()->height() - this->height();

        move(myLabelNewx, myLabelNewy);
        update();
    }
}

/*!
 * \brief XPushButtonFunction::gettTraversalInstanceStatus
 * \return
 */
bool XPushButtonFunction::gettTraversalInstanceStatus() const
{
    return traversalInstanceStatus;
}

/*!
 * \brief XPushButtonFunction::getPushButtonBoolStatus
 * \return
 */
bool XPushButtonFunction::getPushButtonBoolStatus() const
{
    return xPushButtonFunctionP->pushButtonBoolStatus;
}

/*!
 * \brief XPushButtonFunction::insertFunction
 * \param status
 * \param func
 */
void XPushButtonFunction::insertFunction(const PushButtonStatus status, XFunction &xFunction, Function &function)
{
    QMutexLocker locker(&mutex);
    //根据状态选择添加入不同的函数列表
    switch(status)
    {
    case PressInstance:
    {
        ++xPushButtonFunctionP->pressInstanceMap.length;
        xPushButtonFunctionP->pressInstanceMap.xFunctionMap.insert(xPushButtonFunctionP->pressInstanceMap.length, xFunction);
        xPushButtonFunctionP->pressInstanceMap.functionMap.insert(xPushButtonFunctionP->pressInstanceMap.length, function);
        break;
    }
    case PressStatus:
    {
        ++xPushButtonFunctionP->pressStatusMap.length;
        xPushButtonFunctionP->pressStatusMap.xFunctionMap.insert(xPushButtonFunctionP->pressStatusMap.length, xFunction);
        xPushButtonFunctionP->pressStatusMap.functionMap.insert(xPushButtonFunctionP->pressStatusMap.length, function);
        break;
    }
    case ReleaseInstance:
    {
        ++xPushButtonFunctionP->releaseInstanceMap.length;
        xPushButtonFunctionP->releaseInstanceMap.xFunctionMap.insert(xPushButtonFunctionP->releaseInstanceMap.length, xFunction);
        xPushButtonFunctionP->releaseInstanceMap.functionMap.insert(xPushButtonFunctionP->releaseInstanceMap.length, function);
        break;
    }
    case ReleaseStatus:
    {
        ++xPushButtonFunctionP->releaseStatusMap.length;
        xPushButtonFunctionP->releaseStatusMap.xFunctionMap.insert(xPushButtonFunctionP->releaseStatusMap.length, xFunction);
        xPushButtonFunctionP->releaseStatusMap.functionMap.insert(xPushButtonFunctionP->releaseStatusMap.length, function);
        break;
    }
    }
}

/*!
 * \brief XPushButtonFunction::deleteFunction
 * \param status
 * \param index
 * \return
 */
bool XPushButtonFunction::deleteFunction(const PushButtonStatus status, const int index)
{
    QMutexLocker locker(&mutex);

    if(0 >= index)
        return false;

    //声明一个map容器
    QMap<int, XFunction> *xFunctionMap;
    QMap<int, Function> *functionMap;
    //根据状态选择函数列表
    switch(status)
    {
    case PressInstance:
    {
        if(xPushButtonFunctionP->pressInstanceMap.length < index)
            return false;

        xFunctionMap = &xPushButtonFunctionP->pressInstanceMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->pressInstanceMap.functionMap;
        break;
    }
    case PressStatus:
    {
        if(xPushButtonFunctionP->pressInstanceMap.length < index)
            return false;

        xFunctionMap = &xPushButtonFunctionP->pressStatusMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->pressStatusMap.functionMap;
        break;
    }
    case ReleaseInstance:
    {
        if(xPushButtonFunctionP->pressInstanceMap.length < index)
            return false;

        xFunctionMap = &xPushButtonFunctionP->releaseInstanceMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->releaseInstanceMap.functionMap;
        break;
    }
    case ReleaseStatus:
    {
        if(xPushButtonFunctionP->pressInstanceMap.length < index)
            return false;

        xFunctionMap = &xPushButtonFunctionP->releaseStatusMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->releaseStatusMap.functionMap;
        break;
    }
    }

    //查找删除项并删除
    QMap<int, XFunction> ::iterator i = xFunctionMap->begin();
    QMap<int, Function> ::iterator j = functionMap->begin();
    while (i != xFunctionMap->end())
    {
        if(index == i.key())
        {
            xFunctionMap->erase(i++);
            functionMap->erase(j++);
            break;
        }
        ++i;
        ++j;
    }

    //根据状态更新函数列表长度
    switch(status)
    {
    case PressInstance:
    {
        --(xPushButtonFunctionP->pressInstanceMap.length);
        break;
    }
    case PressStatus:
    {
        --(xPushButtonFunctionP->pressStatusMap.length);
        break;
    }
    case ReleaseInstance:
    {
        --(xPushButtonFunctionP->releaseInstanceMap.length);
        break;
    }
    case ReleaseStatus:
    {
        --(xPushButtonFunctionP->releaseStatusMap.length);
        break;
    }
    }

    //如果删的就是最后一个，则不用移动元素直接返回
    if(i == xFunctionMap->end())
        return true;

    //删除处位置后所有元素都向前移动
    while (i != xFunctionMap->end())
    {
        xFunctionMap->insert((i.key() - 1), i.value());
        functionMap->insert((j.key() - 1), j.value());
        ++i;
        ++j;
    }
    //删除最后一个元素
    xFunctionMap->erase(i - 1);
    functionMap->erase(j - 1);

    return true;
}

/*!
 * \brief XPushButtonFunction::moveUpFunction
 * \param status
 * \param index
 */
void XPushButtonFunction::moveUpFunction(const PushButtonStatus status, const int index)
{
    QMutexLocker locker(&mutex);
    //The first one cannot be moved up.
    if(1 >= index)
        return;

    //声明一个map容器
    QMap<int, XFunction> *xFunctionMap;
    QMap<int, Function> *functionMap;
    //根据状态选择函数列表
    switch(status)
    {
    case PressInstance:
    {
        if(xPushButtonFunctionP->pressInstanceMap.length < index)
            return;

        xFunctionMap = &xPushButtonFunctionP->pressInstanceMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->pressInstanceMap.functionMap;
        break;
    }
    case PressStatus:
    {
        if(xPushButtonFunctionP->pressStatusMap.length < index)
            return;

        xFunctionMap = &xPushButtonFunctionP->pressStatusMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->pressStatusMap.functionMap;
        break;
    }
    case ReleaseInstance:
    {
        if(xPushButtonFunctionP->releaseInstanceMap.length < index)
            return;

        xFunctionMap = &xPushButtonFunctionP->releaseInstanceMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->releaseInstanceMap.functionMap;
        break;
    }
    case ReleaseStatus:
    {
        if(xPushButtonFunctionP->releaseStatusMap.length < index)
            return;

        xFunctionMap = &xPushButtonFunctionP->releaseStatusMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->releaseStatusMap.functionMap;
        break;
    }
    }

    //查找上移项并移动位置
    QMap<int, XFunction> ::iterator i = xFunctionMap->begin();
    QMap<int, Function> ::iterator j = functionMap->begin();
    while (i != xFunctionMap->end())
    {
        if(index != i.key())
        {
            ++i;
            ++j;
            continue;
        }

        //上下交换位置
        XFunction xFunctionBuffer = i.value();
        Function functionBuffer = j.value();

        i.value() = (i - 1).value();
        j.value() = (j - 1).value();
        (i - 1).value() = xFunctionBuffer;
        (j - 1).value() = functionBuffer;

        break;
    }
}

/*!
 * \brief XPushButtonFunction::moveDownFunction
 * \param status
 * \param index
 */
void XPushButtonFunction::moveDownFunction(const PushButtonStatus status, const int index)
{
    QMutexLocker locker(&mutex);

    if(1 > index)
        return;

    //声明一个map容器
    QMap<int, XFunction> *xFunctionMap;
    QMap<int, Function> *functionMap;
    //根据状态选择函数列表
    switch(status)
    {
    case PressInstance:
    {
        if(xPushButtonFunctionP->pressInstanceMap.length <= index)
            return;

        xFunctionMap = &xPushButtonFunctionP->pressInstanceMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->pressInstanceMap.functionMap;
        break;
    }
    case PressStatus:
    {
        if(xPushButtonFunctionP->pressStatusMap.length <= index)
            return;

        xFunctionMap = &xPushButtonFunctionP->pressStatusMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->pressStatusMap.functionMap;
        break;
    }
    case ReleaseInstance:
    {
        if(xPushButtonFunctionP->releaseInstanceMap.length <= index)
            return;

        xFunctionMap = &xPushButtonFunctionP->releaseInstanceMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->releaseInstanceMap.functionMap;
        break;
    }
    case ReleaseStatus:
    {
        if(xPushButtonFunctionP->releaseStatusMap.length <= index)
            return;

        xFunctionMap = &xPushButtonFunctionP->releaseStatusMap.xFunctionMap;
        functionMap = &xPushButtonFunctionP->releaseStatusMap.functionMap;
        break;
    }
    }

    //查找下移项并移动位置
    QMap<int, XFunction> ::iterator i = xFunctionMap->begin();
    QMap<int, Function> ::iterator j = functionMap->begin();
    while (i != xFunctionMap->end())
    {
        if(index != i.key())
        {
            ++i;
            ++j;
            continue;
        }

        XFunction xFunctionBuffer = i.value();
        Function functionBuffer = j.value();
        i.value() = (i + 1).value();
        j.value() = (j + 1).value();
        (i + 1).value() = xFunctionBuffer;
        (j + 1).value() = functionBuffer;

        break;
    }
}

/*!
 * \brief XPushButtonFunction::traversalPressInstanceMap
 */
void XPushButtonFunction::traversalPressInstanceMap()
{
    QMutexLocker locker(&mutex);

    QMap<int, XFunction> ::const_iterator i = xPushButtonFunctionP->pressInstanceMap.xFunctionMap.constBegin();
    QMap<int, Function> ::const_iterator j = xPushButtonFunctionP->pressInstanceMap.functionMap.constBegin();
    while (i != xPushButtonFunctionP->pressInstanceMap.xFunctionMap.constEnd())
    {
        XFunction xFunction = i.value();
        Function function = j.value();
        (xFunction.*function)();
        ++i;
        ++j;
    }
}

/*!
 * \brief XPushButtonFunction::traversalPressStatusMap
 */
void XPushButtonFunction::traversalPressStatusMap()
{
    QMutexLocker locker(&mutex);

    QMap<int, XFunction> ::const_iterator i = xPushButtonFunctionP->pressStatusMap.xFunctionMap.constBegin();
    QMap<int, Function> ::const_iterator j = xPushButtonFunctionP->pressStatusMap.functionMap.constBegin();
    while (i != xPushButtonFunctionP->pressStatusMap.xFunctionMap.constEnd())
    {
        XFunction xFunction = i.value();
        Function function = j.value();
        (xFunction.*function)();
        ++j;
        ++i;
    }
}

/*!
 * \brief XPushButtonFunction::traversalReleaseInstanceMap
 */
void XPushButtonFunction::traversalReleaseInstanceMap()
{
    QMutexLocker locker(&mutex);

    QMap<int, XFunction> ::const_iterator i = xPushButtonFunctionP->releaseInstanceMap.xFunctionMap.constBegin();
    QMap<int, Function> ::const_iterator j = xPushButtonFunctionP->releaseInstanceMap.functionMap.constBegin();
    while (i != xPushButtonFunctionP->releaseInstanceMap.xFunctionMap.constEnd())
    {
        XFunction xFunction = i.value();
        Function function = j.value();
        (xFunction.*function)();
        ++j;
        ++i;
    }
}

/*!
 * \brief XPushButtonFunction::traversalReleaseStatusMap
 */
void XPushButtonFunction::traversalReleaseStatusMap()
{
    QMutexLocker locker(&mutex);

    QMap<int, XFunction> ::const_iterator i = xPushButtonFunctionP->releaseStatusMap.xFunctionMap.constBegin();
    QMap<int, Function> ::const_iterator j = xPushButtonFunctionP->releaseStatusMap.functionMap.constBegin();
    while (i != xPushButtonFunctionP->releaseStatusMap.xFunctionMap.constEnd())
    {
        XFunction xFunction = i.value();
        Function function = j.value();
        (xFunction.*function)();
        ++j;
        ++i;
    }
}

/*!
 * \brief XPushButtonFunctionWorker::doWork
 * \param pushButtonFunction
 */
XPushButtonFunctionWorker::XPushButtonFunctionWorker(XPushButtonFunction *parent)
{
    pushButtonFunction = parent;
}

/*!
 * \brief XPushButtonFunctionWorker::doWork
 * \param pushButtonFunction
 */
void XPushButtonFunctionWorker::doWork()
{
    isStop = false;

    while(1)
    {
        Sleep(100);

        if(isStop)
        {
            return;
        }

        bool traversalInstanceStatus = pushButtonFunction->gettTraversalInstanceStatus();
        bool pushButtonStatus = pushButtonFunction->getPushButtonBoolStatus();

        //如果正在遍历瞬时函数列表则暂时不遍历状态函数列表
        if(traversalInstanceStatus)
            continue;

        //如果按钮为按下状态则遍历按下状态列表
        //       为释放状态则遍历释放状态列表
        if(pushButtonStatus)
        {
            //遍历按下状态列表
            pushButtonFunction->traversalPressStatusMap();
        }
        else
        {
            //遍历释放状态列表
            pushButtonFunction->traversalReleaseStatusMap();
        }
    }
}

/*!
 * \brief XPushButtonFunctionWorker::stop
 */
void XPushButtonFunctionWorker::stop()
{
    QMutexLocker locker(&mutex);
    isStop = true;
}

